<?php

declare(strict_types=1);

namespace app\service\notify;

use app\model\NotifyRecipient;
use app\model\NotifyMessage;
use think\facade\Log;
use GatewayWorker\Lib\Gateway;
use app\service\sys\ConfigService;

class SendNotifyService
{
    // 默认重试配置
    private array $defaultRetryConfig = [
        'max_attempts' => 10,
        'intervals' => [60, 120, 300, 600, 1800, 3600, 7200, 21600, 43200, 86400] // 单位：秒
    ];
    
    // 处理统计信息
    private $processStats = [
        'pending_processed' => 0,
        'resend_should' => 0,
        'resend_processed' => 0
    ];

    public function __construct(private ConfigService $configService)
    {
        $config = $this->configService->get('notify.retry');
        if (is_array($config)) {
            $this->defaultRetryConfig = array_replace($this->defaultRetryConfig, array_intersect_key($config, $this->defaultRetryConfig));
        }
    }

    /**
     * 处理通知队列（主入口）
     */
    public function process()
    {
        Log::info("开始处理通知队列");
        
        // 重置统计信息
        $this->processStats = [
            'pending_processed' => 0,
            'resend_should' => 0,
            'resend_processed' => 0
        ];
        
        // 处理待发送的通知
        $pendingCount = $this->processPendingNotifications();
        $this->processStats['pending_processed'] = $pendingCount;
        Log::info("待发送通知处理完成.data:" . json_encode(['processed_count' => $pendingCount]));

        // 处理需要重发的已发送但未读通知
        $resendCount = $this->processUnreadNotifications();
        Log::info("重发通知处理完成.data:" . json_encode(['processed_count' => $resendCount]));
        
        Log::info("通知队列处理结束");
    }
    
    /**
     * 获取处理统计信息
     * 
     * @return array
     */
    public function getProcessStats(): array
    {
        return $this->processStats;
    }

    /**
     * 处理待发送的通知（状态为 PENDING 的通知）
     * 
     * @return int 处理的通知数量
     */
    protected function processPendingNotifications(): int
    {
        Log::info("开始处理待发送通知");
        
        // 获取待发送的通知（状态为待发送）
        $recipients = NotifyRecipient::where('status', NotifyRecipient::STATUS_PENDING)
            ->limit(50)
            ->select();

        Log::info("找到待发送通知.data:" . json_encode(['count' => count($recipients)]));

        $processedCount = 0;
        foreach ($recipients as $recipient) {
            Log::info("处理待发送通知.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'message_id' => $recipient->message_id,
                'target_type' => $recipient->target_type,
                'target_id' => $recipient->target_id
            ]));
            
            if ($this->sendNotification($recipient)) {
                $processedCount++;
            }
        }
        
        return $processedCount;
    }

    /**
     * 处理已发送但未读的通知（重发逻辑）
     * 
     * @return int 处理的通知数量
     */
    protected function processUnreadNotifications(): int
    {
        Log::info("开始处理已发送但未读通知");
        
        // 获取已发送但未读的通知
        $recipients = $this->getUnreadResendNotifications(50);
        
        Log::info("找到需要重发的通知.data:" . json_encode(['count' => count($recipients)]));

        $shouldResendCount = 0;
        $processedCount = 0;
        foreach ($recipients as $recipient) {
            Log::info("检查是否需要重发.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'message_id' => $recipient->message_id,
                'target_type' => $recipient->target_type,
                'target_id' => $recipient->target_id,
                'send_attempts' => $recipient->send_attempts,
                'should_resend' => $this->shouldResend($recipient)
            ]));

            // 检查是否应该重发
            if ($this->shouldResend($recipient)) {
                $shouldResendCount++;
                $this->processStats['resend_should'] = $shouldResendCount;
                Log::info("重发通知.data:" . json_encode(['recipient_id' => $recipient->id]));
                if ($this->resendNotification($recipient)) {
                    $processedCount++;
                    $this->processStats['resend_processed'] = $processedCount;
                }
            }
        }
        
        Log::info("重发通知统计.data:" . json_encode([
            'should_resend_count' => $shouldResendCount,
            'processed_count' => $processedCount
        ]));

        return $processedCount;
    }

    /**
     * 获取已发送但未读且需要重发的通知
     * 
     * @param int $limit 获取数量限制
     * @return \think\Collection
     */
    public function getUnreadResendNotifications(int $limit = 100)
    {
        try {
            // 获取已发送但未读的通知（在合理尝试次数范围内）
            return NotifyRecipient::where('status', NotifyRecipient::STATUS_SENT)
                ->where('read_time', null)
                ->where('send_attempts', '<=', $this->defaultRetryConfig['max_attempts'])
                ->limit($limit)
                ->select();
        } catch (\Exception $e) {
            Log::error('获取已发送未读通知失败.data:' . json_encode(['error' => $e->getMessage()]));
            return collect([]); // 返回空的集合
        }
    }

    /**
     * 判断是否应该重发通知
     * 根据尝试次数和配置的时间间隔来判断
     * 
     * @param NotifyRecipient $recipient 通知接收者
     * @return bool
     */
    protected function shouldResend(NotifyRecipient $recipient): bool
    {
        // 如果已达到最大尝试次数，不重发
        if ($recipient->send_attempts >= $this->defaultRetryConfig['max_attempts']) {
            Log::debug("不重发：已达到最大尝试次数.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'send_attempts' => $recipient->send_attempts,
                'max_attempts' => $this->defaultRetryConfig['max_attempts']
            ]));
            return false;
        }

        // 获取当前尝试次数对应的间隔时间（索引从0开始）
        $attemptIndex = $recipient->send_attempts - 1;
        $interval = $this->defaultRetryConfig['intervals'][$attemptIndex] ?? end($this->defaultRetryConfig['intervals']);

        // 检查距离上次更新是否已经超过间隔时间
        $lastUpdateTime = strtotime($recipient->update_time ?? $recipient->create_time);
        if ($lastUpdateTime === false) {
            $lastUpdateTime = time(); // 如果时间解析失败，默认使用当前时间
        }

        $currentTime = time();
        $timeDiff = $currentTime - $lastUpdateTime;
        
        $shouldResend = $timeDiff >= $interval;
        
        Log::debug("重发判断.data:" . json_encode([
            'recipient_id' => $recipient->id,
            'send_attempts' => $recipient->send_attempts,
            'last_update_time' => $recipient->update_time ?? $recipient->create_time,
            'last_update_timestamp' => $lastUpdateTime,
            'current_time' => $currentTime,
            'time_diff' => $timeDiff,
            'interval' => $interval,
            'should_resend' => $shouldResend
        ]));

        // 如果距离上次更新的时间超过间隔时间，则应该重发
        return $shouldResend;
    }

    /**
     * 发送通知给指定接收者（首次发送）
     * 
     * @param NotifyRecipient $recipient 通知接收者
     * @return bool 是否发送成功
     */
    public function sendNotification(NotifyRecipient $recipient): bool
    {
        try {
            // 确保关联的消息已加载
            if (!$recipient->message) {
                $recipient->load(['message']);
            }

            // 获取消息内容
            $message = $recipient->message;

            // 检查消息是否存在
            if (!$message) {
                Log::warning("通知消息不存在.data:" . json_encode(['recipient_id' => $recipient->id]));
                // 标记为失败
                $recipient->save([
                    'status' => NotifyRecipient::STATUS_FAILED,
                    'send_attempts' => $recipient->send_attempts + 1,
                ]);
                return false;
            }

            // 构造发送数据
            $nextAttempt = $recipient->send_attempts + 1;

            $data = [
                'type' => 'notification',
                'message_id' => (int) $message->id,
                'recipient_id' => (int) $recipient->id,
                'target_type' => $recipient->target_type,
                'target_id' => (int) $recipient->target_id,
                'title' => $message->title,
                'content' => $message->content,
                'payload' => $message->payload,
                'attempt' => $nextAttempt,
            ];

            Log::info("准备发送通知.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'target_type' => $recipient->target_type,
                'target_id' => $recipient->target_id,
                'message_id' => $message->id
            ]));

            // 发送通知到组
            $group = $recipient->target_id > 0
                ? $recipient->target_type . '_' . $recipient->target_id
                : $recipient->target_type;
            Gateway::sendToGroup($group, json_encode($data));

            Log::info("通知发送成功.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'group' => $group
            ]));

            // 更新状态为已发送，并增加尝试次数
            $recipient->save([
                'status' => NotifyRecipient::STATUS_SENT,
                'send_attempts' => $nextAttempt,
            ]);

            return true;
        } catch (\Exception $e) {
            // 增加尝试次数
            $newAttempts = $recipient->send_attempts + 1;

            // 准备更新数据
            $updateData = [
                'send_attempts' => $newAttempts,
            ];

            // 如果达到最大尝试次数，标记为最终失败
            if ($newAttempts >= $this->defaultRetryConfig['max_attempts']) {
                $updateData['status'] = NotifyRecipient::STATUS_FAILED;
                Log::error("通知发送最终失败，已达到最大尝试次数.data:" . json_encode([
                    'recipient_id' => $recipient->id,
                    'target_id' => $recipient->target_id,
                    'attempts' => $newAttempts,
                    'error' => $e->getMessage()
                ]));
            } else {
                // 否则标记为失败状态，等待下次重试
                Log::warning("通知发送失败，将进行重试.data:" . json_encode([
                    'recipient_id' => $recipient->id,
                    'target_id' => $recipient->target_id,
                    'attempts' => $newAttempts,
                    'error' => $e->getMessage()
                ]));
            }
            
            // 更新发送失败状态
            $recipient->save($updateData);
            return false;
        }
    }

    /**
     * 重新发送通知给指定接收者
     * 
     * @param NotifyRecipient $recipient 通知接收者
     * @return bool 是否重发成功
     */
    public function resendNotification(NotifyRecipient $recipient): bool
    {
        try {
            // 确保关联的消息已加载
            if (!$recipient->message) {
                $recipient->load(['message']);
            }

            // 获取消息内容
            $message = $recipient->message;

            // 检查消息是否存在
            if (!$message) {
                Log::warning("通知消息不存在.data:" . json_encode(['recipient_id' => $recipient->id]));
                return false;
            }

            // 构造发送数据
            $nextAttempt = $recipient->send_attempts + 1;

            $data = [
                'type' => 'notification',
                'message_id' => (int) $message->id,
                'recipient_id' => (int) $recipient->id,
                'target_type' => $recipient->target_type,
                'target_id' => (int) $recipient->target_id,
                'title' => $message->title,
                'content' => $message->content,
                'payload' => $message->payload,
                'created_at' => $message->create_time ?? date('Y-m-d H:i:s'),
                'attempt' => $nextAttempt,
            ];

            Log::info("准备重新发送通知.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'target_type' => $recipient->target_type,
                'target_id' => $recipient->target_id,
                'message_id' => $message->id
            ]));

            // 发送通知到组
            $group = $recipient->target_id > 0
                ? $recipient->target_type . '_' . $recipient->target_id
                : $recipient->target_type;
            Gateway::sendToGroup($group, json_encode($data));

            // 增加发送尝试次数
            $recipient->save([
                'send_attempts' => $nextAttempt,
            ]);

            Log::info("通知重新发送成功.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'group' => $group
            ]));
            
            return true;
        } catch (\Exception $e) {
            // 增加尝试次数
            $newAttempts = $recipient->send_attempts + 1;

            // 准备更新数据
            $updateData = [
                'send_attempts' => $newAttempts,
                'failed_reason' => $e->getMessage()
            ];

            // 如果达到最大尝试次数，标记为最终失败
            if ($newAttempts >= $this->defaultRetryConfig['max_attempts']) {
                $updateData['status'] = NotifyRecipient::STATUS_FAILED;
                Log::error("通知重新发送最终失败，已达到最大尝试次数.data:" . json_encode([
                    'recipient_id' => $recipient->id,
                    'target_id' => $recipient->target_id,
                    'attempts' => $newAttempts,
                    'error' => $e->getMessage()
                ]));
            }

            // 更新发送失败状态
            $recipient->save($updateData);

            Log::warning("通知重新发送失败.data:" . json_encode([
                'recipient_id' => $recipient->id,
                'target_id' => $recipient->target_id,
                'attempts' => $newAttempts,
                'error' => $e->getMessage()
            ]));

            return false;
        }
    }
}
